package actorservice

import (
	"fmt"
	"go.uber.org/zap"
	"time"
	"wzgames/pkg/actor/actor"
	"wzgames/pkg/logger"
)

var actorSystem = actor.NewActorSystem()

type IService interface {
	IServiceMeta
	OnReceive(context actor.Context)
	OnInit()
	OnStart(as *ActorService)
	OnDestroy()
}

type ActorService struct {
	inst IService
	args []interface{}
}

func (as *ActorService) Receive(context actor.Context) {
	switch context.Message().(type) {
	case *actor.Started:
		fmt.Println("Started, initialize actor here")
	case *actor.Stopping:
		fmt.Println("Stopping, actor is about shut down")
	case *actor.Stopped:
		fmt.Println("Stopped, actor and its children are stopped")
	case *actor.Restarting:
		fmt.Println("Restarting, actor is about restart")
	default:
		as.inst.OnReceive(context)
	}
}

func (as *ActorService) Args() []interface{} {
	return as.args
}

func StartService(inst IService, args ...interface{}) error {
	as := &ActorService{
		inst: inst,
		args: args,
	}
	props := actor.PropsFromProducer(func() actor.Actor { return as })
	pid, err := actorSystem.Root.SpawnNamed(props, inst.GetName())
	if err != nil {
		logger.Error("spawn actor error", zap.Error(err))
		return err
	}
	inst.SetPID(pid)
	inst.OnStart(as)
	return nil
}

func Send(pid *actor.PID, msg interface{}) {
	if pid == nil {
		return
	}
	actorSystem.Root.Send(pid, msg)
}

func RequestFuture(pid *actor.PID, msg interface{}, timeout time.Duration) (interface{}, error) {
	future := actorSystem.Root.RequestFuture(pid, msg, timeout)
	return future.Result()
}

func Stop(pid *actor.PID) {
	actorSystem.Root.Stop(pid)
}

func ActorSystem() *actor.ActorSystem {
	return actorSystem
}
